package com.jacky.demo.opengl;

import android.graphics.Bitmap;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLUtils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

/**
 * Created by lixinquan on 2019/3/1.
 */
public class GlUtils {

    static float cameraFrontVertexData[] = {  //前置摄像头
            1.0f, -1.0f,
            1.0f, 1.0f,
            -1.0f, -1.0f,
            -1.0f, 1.0f,
    };
    static float cameraBackVertexData[] = { //后置摄像头
            1.0f, 1.0f,
            1.0f, -1.0f,
            -1.0f, 1.0f,
            -1.0f, -1.0f,
    };
    static float cameraTextureData[] = {
            0.0f, 0.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
    };
    static float waterMaskVertexData[] = {
            -1f, 1f, // top left
            1f, 1f,  // top right
            -1f, -1f, // bottom left
            1f, -1f, // bottom right
    };
    //纹理坐标  对应顶点坐标  与之映射
    static float waterMaskTextureData[] = {
            0f, 0f, // top left
            1f, 0f,  // top right
            0f, 1f, // bottom left
            1f, 1f, // bottom right
    };

    static float vertexData[] = {   // in counterclockwise order:
            -1f, -1f, // bottom left
            1f, -1f, // bottom right
            -1f, 1f, // top left
            1f, 1f,  // top right
    };

    //纹理坐标  对应顶点坐标  与之映射
    static float textureData[] = {   // in counterclockwise order:
            0f, 0f, // top left
            1f, 0f,  // top right
            0f, 1f, // bottom left
            1f, 1f, // bottom right
    };

    static FloatBuffer vertexBuffer = allocateFloatBuffer(vertexData);
    static FloatBuffer textureBuffer = allocateFloatBuffer(textureData);

    final static String vertexShaderCode =
            "attribute vec4 av_Position;" +
                    "attribute vec2 af_Position;" +
                    "varying vec2 textureCoordinate;" +
                    "void main() {" +
                    "   gl_Position = av_Position;" +
                    "   textureCoordinate = af_Position;" +
                    "}";

    final static String fragmentShaderCode =
            "#extension GL_OES_EGL_image_external : require\n" +
                    "precision mediump float;" +
                    "varying vec2 textureCoordinate;" +
                    "uniform samplerExternalOES s_texture;" +
                    "void main() {" +
                    "   gl_FragColor = texture2D(s_texture, textureCoordinate );" +
                    "}";

    public static final String waterVertexShader =
            "attribute vec4 av_Position;" +
                    "attribute vec2 af_Position;" +
                    "varying vec2 v_texPo;" +
                    "void main() {" +
                    "    v_texPo = af_Position;" +
                    "    gl_Position = av_Position;" +
                    "}";

    public static final String waterFragmentShader =
            "precision mediump float;" +
                    "varying vec2 v_texPo;" +
                    "uniform sampler2D sTexture;" +
                    "void main() {" +
                    "    gl_FragColor=texture2D(sTexture, v_texPo);" +
                    "}";

    public static int loadShader(int type, String shaderCode) {
        // 创造顶点着色器类型(GLES20.GL_VERTEX_SHADER)
        // 或者是片段着色器类型 (GLES20.GL_FRAGMENT_SHADER)
        int shader = GLES20.glCreateShader(type);
        // 添加上面编写的着色器代码并编译它
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }

    public static int createProgram(String verTextShader, String fragmentShader) {
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, verTextShader);
        int fragShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
        //创建一个空的OpenGLES程序
        int program = GLES20.glCreateProgram();
        //将顶点着色器加入到程序
        GLES20.glAttachShader(program, vertexShader);
        //将片元着色器加入到程序中
        GLES20.glAttachShader(program, fragShader);
        //连接到着色器程序
        GLES20.glLinkProgram(program);
        return program;
    }

    public static FloatBuffer allocateFloatBuffer(float[] vertices) {
        return allocateFloatBuffer(null, vertices);
    }

    public static FloatBuffer allocateFloatBuffer(FloatBuffer vertexBuffer, float[] vertices) {
        if(vertexBuffer == null) {
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
            byteBuffer.order(ByteOrder.nativeOrder());
            vertexBuffer = byteBuffer.asFloatBuffer();
        } else {
            vertexBuffer.clear();
        }
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);
        return vertexBuffer;
    }

    public static ShortBuffer allocateShortBuffer(short[] vertices) {
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 2);
        byteBuffer.order(ByteOrder.nativeOrder());
        ShortBuffer vertexBuffer = byteBuffer.asShortBuffer();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);
        return vertexBuffer;
    }

    public static int createTextureID() {
        int[] texture = new int[1];
        GLES20.glGenTextures(1, texture, 0);
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[0]);
        glTexParameter(true);
        return texture[0];
    }

    public static int bindTexture(Bitmap bm) {
        if (bm == null) return 0;
        int[] textures = new int[1];
        GLES20.glGenTextures(1, textures, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
        glTexParameter(false);
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bm, 0);
        return textures[0];
    }

    public static void glTexParameter(boolean isOes) {
        int target = isOes ? GLES11Ext.GL_TEXTURE_EXTERNAL_OES : GLES20.GL_TEXTURE_2D;
        //设置缩小过滤为使用纹理中坐标最接近的一个像素的颜色作为需要绘制的像素颜色
        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        //设置放大过滤为使用纹理中坐标最接近的若干个颜色，通过加权平均算法得到需要绘制的像素颜色
        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        //设置环绕方向S，截取纹理坐标到[1/2n,1-1/2n]。将导致永远不会与border融合
        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        //设置环绕方向T，截取纹理坐标到[1/2n,1-1/2n]。将导致永远不会与border融合
        GLES20.glTexParameterf(target, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
    }
}
